package com.boot.commoncore.utils;


import com.boot.commondomain.constants.CommonConstants;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

// JSON工具类:提供序列化和反序列化功能
@Slf4j
public class JsonUtil {
    //静态私有,JsonUtil类内的所有地方都共享该对象
    private static ObjectMapper OBJECT_MAPPER;

    //静态代码块初始化:类加载时期进行
    static {
        OBJECT_MAPPER = JsonMapper.builder()
                // 反序列化:针对JSON中未知属性(对象没有的属性),true(默认)抛出异常;false忽略未知属性
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                // 序列化:针对对象中属性为Date类型(日期),true(默认)序列化为时间戳;false序列化为日期(可结合defaultDateFormat配置可格式化日期)
                .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
                // 序列化:针对对象中没有任何属性,true(默认)抛出异常;false忽略异常得到空JSON对象
                .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
                // 反序列化:针对JSON中指定类型信息(Jackson相关注解可能需要在JSON字符串中定义属性和对应类型)与对象类型不匹配
                // true(默认)抛出异常;false忽略异常尝试转化为能兼容的对象
                // 比如false值:一个父类A 两个子类B和C,JSON中包含与注解相关的类型属性为B,但是要反序列化为C,虽然类型不匹配,但是会尝试(如果有相关父子类序列化注解)反序列化为父类A
                .configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false)
                // 序列化:针对对象以Date类型(日期)为Key(比如Map中键位Date类型),true序列化为时间戳;false(默认)序列化为日期(可结合defaultDateFormat配置可格式化日期)
                .configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, false)
                // true(默认)允许添加Jackson相关注解定义序列化和反序列化行为;false不允许使用注解(强行使用可能导致序列化或反序列化失败)
                .configure(MapperFeature.USE_ANNOTATIONS, false)
                // 添加序列化LocalDateTime和LocalDate类型日期属性的必要参数,Jackson-data-JSR310实现
                .addModule(new JavaTimeModule())
                // 添加序列化和反序列化LocalDateTime和LocalDate类型日期属性时日期格式
                .addModule(new SimpleModule()
                        .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(CommonConstants.STANDARD_FORMAT)))
                        .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(CommonConstants.STANDARD_FORMAT)))
                )
                // 添加序列化和反序列化Date类型日期属性时日期格式
                .defaultDateFormat(new SimpleDateFormat(CommonConstants.STANDARD_FORMAT))
                // 序列化:只对对象的非空属性序列化
                .serializationInclusion(JsonInclude.Include.NON_NULL)
                .build();
    }
    /**
     * 禁用构造
     */
    private JsonUtil() {
    }

    /**
     * 对象转JSON字符串
     *
     * @param obj 对象
     * @param <T> 泛型指明对象类型
     * @return JSON字符串
     */
    public static <T> String objectToString(T obj) {
        if (obj == null) {
            return null;
        }
        try {
            return obj instanceof String ? (String) obj : OBJECT_MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            log.warn("Parse Object to String error : {}", e.getMessage());
            return null;
        }
    }

    /**
     * 对象转JSON字符串(格式化的JSON字符串)
     *
     * @param obj 对象
     * @param <T> 泛型指明对象类型
     * @return 格式化的JSON字符串
     */
    public static <T> String objectToStringPretty(T obj) {
        if (obj == null) {
            return null;
        }
        try {
            return obj instanceof String ? (String) obj : OBJECT_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            log.warn("Parse Object to String error : {}", e.getMessage());
            return null;
        }
    }

    /**
     * 字符串转对象(对象类型为简单类型,即不支持嵌套,存在泛型擦除问题)
     *
     * @param str    要转换的字符串
     * @param tClass 自定义对象的class
     * @param <T>    泛型指明对象类型
     * @return 自定义对象
     */
    public static <T> T stringToObject(String str, Class<T> tClass) {
        if (StringUtils.isEmpty(str) || tClass == null) {
            return null;
        }
        try {
            return tClass.equals(String.class) ? (T) str : OBJECT_MAPPER.readValue(str, tClass);
        } catch (Exception e) {
            log.warn("Parse String to Object error : {}", e.getMessage());
            return null;
        }
    }

    /**
     * 字符串转List嵌套对象List<Object>,支持List嵌套简单对象(解决List<T>的泛型擦除问题)
     *
     * @param str   json字符串
     * @param tClass 自定义对象的class对象
     * @param <T>   泛型指明被嵌套的对象类型
     * @return 对象列表
     */
    public static <T> List<T> stringToList(String str, Class<T> tClass) {
        if (StringUtils.isEmpty(str) || tClass == null) {
            return null;
        }
        JavaType javaType = OBJECT_MAPPER.getTypeFactory().constructParametricType(List.class, tClass);
        try {
            return OBJECT_MAPPER.readValue(str, javaType);
        } catch (IOException e) {
            log.error("Parse String to Object error : {}" + e.getMessage());
            return null;
        }
    }

    /**
     * 字符串转Map嵌套对象Map<String,Object>,支持Map嵌套简单对象(解决Map<String, T>的泛型擦除问题)
     *
     * @param str        json字符串
     * @param valueClass Map中key:value中value的类型
     * @param <T>        泛型指明被嵌套的value的类型
     * @return map对象
     */
    public static <T> Map<String, T> stringToMap(String str, Class<T> valueClass) {
        if (StringUtils.isEmpty(str) || valueClass == null) {
            return null;
        }
        JavaType javaType = OBJECT_MAPPER.getTypeFactory().constructMapType(LinkedHashMap.class, String.class, valueClass);
        try {
            return OBJECT_MAPPER.readValue(str, javaType);
        } catch (JsonProcessingException e) {
            log.warn("Parse String to Object error : {}", e.getMessage());
            return null;
        }
    }
    /**
     * 字符串转对象,泛型擦除的复杂泛型嵌套解决方案,比如List<Map<String,Object>>
     *
     * @param str          json字符串
     * @param valueTypeRef 对象模板信息,比如new TypeReference<List<Map<String,Object>>>
     * @param <T>          泛型指明对象类型
     * @return 对象类对应的对象
     */
    public static <T> T stringToObject(String str, TypeReference<T> valueTypeRef) {
        if (StringUtils.isEmpty(str) || valueTypeRef == null) {
            return null;
        }
        try {
            return OBJECT_MAPPER.readValue(str, valueTypeRef);
        } catch (Exception e) {
            log.warn("Parse String to Object error : {}", e.getMessage());
            return null;
        }
    }
}
